重排and重绘

什么是重排,重绘?

在我还是菜菜菜鸟时,有人就问我了。你知道什么操作会引起重排吗?

当时就在想,重排是个什么东东。。。于是,Google了一下(说谷歌显的高大上点(⊙﹏⊙)b)
当然,提到重排重绘,就理所当然会提及DOM树和渲染树等等~ 这就让我们一个个慢慢道来。

高性能JavaScript里是这么说的:

“浏览器下载完页面中的所有组件————HTML标记、JavaScript、CSS、图片————之后就会解析并生成两个内部数据结构

DOM树

表示页面结构

渲染树

表示DOM节点如何显示

DOM树和渲染树就是相互存在的一种数据结构,DOM树里每一个需要显示的节点在渲染树里至少会有一个对应的节点(当然,隐藏的DOM元素在渲染树里是没用节点的)渲染树的节点可以叫“帧”或者“盒”,可以理解为CSS里面的盒子吧,就可以把对应的页面元素理解为一个具有padding,margin,border和position(位置)的盒子。一旦这DOM树和渲染树相互构建完成之后,浏览器就可以要是显示(绘制paint)页面元素了。

可是怎么理解呢,就举个栗子吧,不知道大家画过画没,数字油画呢?就用它来说栗子:

  1. 比如我要画个柯南,你要想把,柯南肯定是个人吧,有眼睛,鼻子,嘴巴,耳朵各种五官吧,当然还要穿衣服吧,可以还可以把他爱人小兰画上吧。就是你画像需要显示的内容就是对应DOM树的节点,他们的集合就构成一棵DOM树吧;
  2. 那当你决定要画的时候,就要构造柯南的头有多大,眼睛大小之类的吧,上什么色吧,就像数字油画给你的那个有数字,不同格子填什么色的,这个格子就是可以当成渲染树的节点,那这个集合构成就是渲染树啦;
  3. 最后,我这个大画家就要开始作画啦,那你画到画布上的过程就是绘制painting啦,painting这个词形象生动O(∩_∩)O~

不知道这样说,清楚没呢~

所以,一旦DOM树变化,影响了页面元素的几何属性(宽高)————比如,改变了元素border或者给段落添加文字增加了行数————这样的话,浏览器就要重新计算元素的几何属性,以及其他受影响的元素。这时浏览器起作用啦,就会让渲染树受影响部分失效,进行重新计算,再重新构造渲染树,这个过程就叫做“重排热flow”,重排完成后,浏览器会把受影响部分的元素重新显示(绘制)到屏幕上,这一过程就叫做“重绘”。就这样理解嘛,活字印刷术里,你要写文字,你的文字都还没有排好,怎么进行印刷呢。

但是呢,并不是有了重排才会有重绘,就比如,你页面元素的几何属性就修改背景颜色,其他都不改,这个行为是没有触发重排的(因为没有修改元素的布局),但是浏览器需要进行一次重绘,把新的背景颜色绘制到屏幕上。

重排怎么触发(发生)?

当页面布局和几何属性改变时就需要重排。举栗子

  • 添加或删除可见DOM元素,注意是可见,不可见的根本就不在渲染树上好吗;
  • 元素位置改变;就如把A移动到B,B移动到A
  • 元素尺寸改变(包括:padding,margin,border,width,height等属性改变时);
  • 内容改变,如文本改变,或者图片被另一个不同尺寸的图片替换
  • 页面渲染器初始化
  • 浏览器窗口尺寸变化,这里我就有点疑问,那要是我每次缩放浏览器不都会触发吗???
  • 最后,页面出现滚动条时也会触发。。。

渲染树变化的排队与刷新

因为每一次的重排都会消耗很大一部分的性能,所以,浏览器一般都会通过队列化修改并批量执行来优化重排过程。但是你可能没注意使用到一些属性,就会强制刷新队列并计划任务立马执行,就马上重排了!!!

获取布局信息的操作会强制队列刷新,所以,以下的属性尽量避免使用!

  • offsetTop,offsetLeft,offsetWidth,offsetHeigt;
  • scrollTop,scrollLeft,scrollWidth,scrollHeight;
  • clientTop,clientLeft,clientWidth,clientHeight;
  • getComputedStyle() (currentStyle in IE)

最小化重绘和重排

改变样式

改变样式时,最后就是,合并所有的改变,然后一次性处理,这样就只会修改DOM一次,做到最小化重排啦

批量修改DOM

方法有很多

  • 为需要修改的节点创建备份,然后对副本进行修改,修改完成后就用它来对旧的节点进行替换
  • (墙裂推荐)使用创建文档片段createDocumentFragment的方法,具体可以看我之前关于文档片段的笔记,因为这种方法产生的DOM遍历和重排次数是最少的。

嗯,重排和重绘就先这样吧。可以结合前面摘的浏览器工作流~